package com.example.fivecheergame;

import android.content.Context;
import android.content.DialogInterface;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.os.Handler;
import android.os.Message;
import android.util.AttributeSet;
import android.util.Log;
import android.view.MotionEvent;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.appcompat.app.AlertDialog;

import java.util.ArrayList;
import java.util.List;
import java.util.Timer;
import java.util.TimerTask;

public class MyView extends View {
    // 面板的宽度=高度
    int panel_width;
    // 每个格子的宽度=高度
    int cell_width;
    // 棋子宽度占格子宽度的比例
    float piece_percent = 0.75F;
    // 每个棋子的宽度=高度
    int piece_width;
    // 画笔
    Paint paint = new Paint();
    // 原始大小的棋子
    Bitmap rawWhitePiece;
    Bitmap rawBlackPiece;
    // 需要绘制的棋子
    Bitmap whitePiece;
    Bitmap blackPiece;
    // 是否已经赢了 赢了结束游戏
    boolean isStop = false;
    // 当前下的是否是白子
    boolean isWhite = false;
    // List分别保存白子 和黑子 的位置
    List<PieceLocation> whitePieceArray = new ArrayList<>();
    List<PieceLocation> blackPieceArray = new ArrayList<>();

    // 设置时间
    /*
    private int i = 15;
    private TextView txtView;
    private Timer timer = null;
    private TimerTask task = null;
    private boolean timeIsStart = false;
    */

    /**     欠缺功能：
     * 1、同一色的四子连成一线，且四子的两端是空棋位。
     * 2、同一色的三子连成一线，两端为空棋位且三子中任意一子在其他方向上与同色棋子三子连成一线。
     * 3、游戏开始，开始计时，每次落子重置原先计时并开始新的计时（15s）
     * 4、联网功能
     * 5、人机对战功能
     */

    public MyView(Context context, @Nullable AttributeSet attrs) {
        super(context, attrs);
        paint.setStrokeWidth(4);
        rawWhitePiece = BitmapFactory.decodeResource(getResources(), R.drawable.stone_w2);
        rawBlackPiece = BitmapFactory.decodeResource(getResources(), R.drawable.stone_b1);
    }

    @Override
    protected void onDraw(Canvas canvas) {
        canvas.drawColor(Color.argb(25, 200, 200, 200));
        // 画十条横线
        drawTenHengXian(canvas);
        // 画十条竖线
        drawTenShuXian(canvas);
        // 绘制白子和黑子的列表
        for(PieceLocation location : whitePieceArray){
            float x = (location.x + (0.5F - piece_percent / 2)) * cell_width;
            float y = (location.y + (0.5F - piece_percent / 2)) * cell_width;
            canvas.drawBitmap(whitePiece, x, y, paint);
        }

        for(PieceLocation location : blackPieceArray){
            float x = (location.x + (0.5F - piece_percent / 2)) * cell_width;
            float y = (location.y + (0.5F - piece_percent / 2)) * cell_width;
            canvas.drawBitmap(blackPiece, x, y, paint);
        }
    }

    @Override
    public boolean onTouchEvent(MotionEvent event) {
        // 如有一方已经赢了 则不能再下了
        if(isStop){
            return true;
        }

        float x = event.getX();
        float y = event.getY();

        switch (event.getAction()){
            case MotionEvent.ACTION_UP:
                PieceLocation location = getPieceLocation(x, y);
                // 先要判断该位置是否已有棋子
                if(whitePieceArray.contains(location) || blackPieceArray.contains(location)){
                    Toast.makeText(getContext(), "这里已有棋子不能再下这里",Toast.LENGTH_SHORT).show();
                    return true;
                }
                // 加入到白子或黑子的位置列表
                if(isWhite){
                    whitePieceArray.add(location);
                }else{
                    blackPieceArray.add(location);
                }
                // 用来判断某一方有没有赢
                judge();

                // 判断棋盘是否已经下满而且未分胜负
                if(whitePieceArray.size() == 50 && blackPieceArray.size() == 50){
                    Toast.makeText(getContext(),"和棋",Toast.LENGTH_SHORT).show();
                    isStop = true;
                }
                isWhite = !isWhite;
                invalidate();
                break;
        }
        return true;
    }

    @Override
    protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
        int width = MeasureSpec.getSize(widthMeasureSpec);
        int height = MeasureSpec.getSize(heightMeasureSpec);
        int min = width;
        if(width > height){
            min = height;
        }
        setMeasuredDimension(min, min);
    }

    @Override
    protected void onSizeChanged(int w, int h, int oldw, int oldh) {
        super.onSizeChanged(w, h, oldw, oldh);
        panel_width = w;
        cell_width = panel_width / 10;
        piece_width = (int) (cell_width * piece_percent);
        // 生成指定大小的棋子
        whitePiece = Bitmap.createScaledBitmap(rawWhitePiece, piece_width, piece_width, false);
        blackPiece = Bitmap.createScaledBitmap(rawBlackPiece, piece_width, piece_width, false);
    }

    /**
     * 判断输赢
     */
    private void judge() {
        if(isWhite){
            if(judgeArray(whitePieceArray)){
                Toast.makeText(getContext(), "恭喜白方获胜！！！",Toast.LENGTH_SHORT).show();
                isStop = true;
            }
        }else{
            if(judgeArray(blackPieceArray)){
                Toast.makeText(getContext(), "恭喜黑方获胜！！！",Toast.LENGTH_SHORT).show();
                isStop = true;
            }
        }
    }

    private boolean judgeArray(List<PieceLocation> pieceArray) {
        if(pieceArray.size() < 5){
            return false;
        }
        // 判断水平方向赢了没
        if(judgeHorizontalArray(pieceArray)){
            return true;
        }
        //判断垂直方向赢了没
        if(judgeVerticalArray(pieceArray)){
            return true;
        }
        //判断右下方向赢了没
        if(judgeRightDownArray(pieceArray)){
            return true;
        }
        //判断右上方向赢了没
        return judgeRightUpArray(pieceArray);
    }

    /**
     * 判断右上(左下)方向有没有赢
     * @param pieceArray
     * @return
     */
    private boolean judgeRightUpArray(List<PieceLocation> pieceArray) {
        for(PieceLocation location:pieceArray){
            int count = 1;
            // 向右上走4个
            for (int i=1; i<5; i++){
                PieceLocation temp = new PieceLocation(location.x+i, location.y-i);
                if(pieceArray.contains(temp)){
                    count++;
                }
            }
            if (count ==5){
                return true;
            }

            //重置count
            count=1;

            // 向左下走4个
            for (int i=1; i<5; i++){
                PieceLocation temp = new PieceLocation(location.x-i, location.y+i);
                if(pieceArray.contains(temp)){
                    count++;
                }
            }
            if (count ==5){
                return true;
            }
        }
        return  false;
    }

    /**
     * 判断右下（左上）方向有没有赢
     * @param pieceArray
     * @return
     */
    private boolean judgeRightDownArray(List<PieceLocation> pieceArray) {
        for(PieceLocation location:pieceArray){
            int count = 1;
            // 向右下走4个
            for (int i=1; i<5; i++){
                PieceLocation temp = new PieceLocation(location.x+i, location.y+i);
                if(pieceArray.contains(temp)){
                    count++;
                }
            }
            if (count ==5){
                return true;
            }

            //重置count
            count=1;

            // 向左上走4个
            for (int i=1; i<5; i++){
                PieceLocation temp = new PieceLocation(location.x-i, location.y-i);
                if(pieceArray.contains(temp)){
                    count++;
                }
            }
            if (count ==5){
                return true;
            }
        }
        return  false;
    }

    /**
     * 判断垂直方向有没有赢
     * @param pieceArray
     * @return
     */
    private boolean judgeVerticalArray(List<PieceLocation> pieceArray) {
        for(PieceLocation location:pieceArray){
            int count = 1;
            // 向上走4个
            for (int i=1; i<5; i++){
                PieceLocation temp = new PieceLocation(location.x, location.y-i);
                if(pieceArray.contains(temp)){
                    count++;
                }
            }

            if (count ==5){
                return true;
            }
            //重置count
            count=1;

            // 向下走4个
            for (int i=1; i<5; i++){
                PieceLocation temp = new PieceLocation(location.x, location.y+i);
                if(pieceArray.contains(temp)){
                    count++;
                }
            }
            if (count ==5){
                return true;
            }
        }
        return  false;
    }

    /**
     * 判断水平方向是否赢了
     * @param pieceArray
     * @return
     */
    private boolean judgeHorizontalArray(List<PieceLocation> pieceArray) {
        for(PieceLocation location:pieceArray){
            int count = 1;
            // 向左走4个
            for (int i=1; i<5; i++){
                PieceLocation temp = new PieceLocation(location.x - i, location.y);
                if(pieceArray.contains(temp)){
                    count++;
                }
            }

            if (count ==5){
                return true;
            }

            //重置count
            count=1;

            // 向右走4个
            for (int i=1; i<5; i++){
                PieceLocation temp = new PieceLocation(location.x + i, location.y);
                if(pieceArray.contains(temp)){
                    count++;
                }
            }

            if (count == 5){
                return true;
            }

        }
        return  false;
    }

    /**
     * 根据触摸的坐标计算棋子的位置
     * @param x 棋子的x轴坐标
     * @param y 棋子的y轴坐标
     * @return 棋子的坐标对象pieceLocation  （x，y）
     */
    private PieceLocation getPieceLocation(float x, float y) {
        PieceLocation pieceLocation = new PieceLocation();
        pieceLocation.x = (int) (x / cell_width);
        pieceLocation.y = (int) (y / cell_width);
        return  pieceLocation;
    }

    /**
     * 画十条竖线
     * @param canvas
     */
    private void drawTenShuXian(Canvas canvas) {
        float startX = cell_width * 0.5F;
        float startY = cell_width * 0.5F;
        float stopX =  cell_width * 0.5F;
        float stopY = panel_width - cell_width * 0.5F;

        for(int i=0; i<10; i++){
            canvas.drawLine(startX + i * cell_width, startY, stopX + i * cell_width, stopY, paint);
        }
    }

    /**
     * 画十条横线
     * @param canvas
     */
    private void drawTenHengXian(Canvas canvas) {
        float startX = cell_width * 0.5F;
        float startY = cell_width * 0.5F;
        float stopX = panel_width - cell_width * 0.5F;
        float stopY = cell_width * 0.5F;

        for(int i=0; i<10; i++){
            canvas.drawLine(startX, startY + i * cell_width, stopX, stopY + i * cell_width, paint);
        }
    }

    /**
     * 游戏重新开始
     */
    public void reStart() {
        whitePieceArray.clear();
        blackPieceArray.clear();
        isWhite = false;
        isStop = false;
        invalidate();
        Toast.makeText(getContext(), "全部清空，已重新开始",Toast.LENGTH_SHORT).show();
    }

    /**
     * 执棋方认输
     * @return
     */
    public boolean defeat() {
        if (isWhite) {
            Toast.makeText(getContext(), "白方认输",Toast.LENGTH_SHORT).show();
        }else {
            Toast.makeText(getContext(), "黑方认输",Toast.LENGTH_SHORT).show();
        }
        isStop = true;
        return false;
    }

    /**
     * 弹窗显示游戏规则
     */
    public void rule() {
        /* @setIcon 设置对话框图标
         * @setTitle 设置对话框标题
         * @setMessage 设置对话框消息提示
         * setXXX方法返回Dialog对象，因此可以链式设置属性
         */
        final AlertDialog.Builder dialog = new AlertDialog.Builder(getContext());
        dialog.setIcon(R.mipmap.ico);
        dialog.setTitle("游戏规则");
        dialog.setMessage("1、对峙双方谁的五个棋子先连在一条线即为胜者。\n"  +
                "2、当有三个子连成一条直线时，就应采取防守，堵住三子的一端，否则就会输掉比赛。\n"
        + "3、应当避免在比赛内出现三三禁手、四四禁手等情况，否则就会不小心输掉比赛。");
        dialog.setNegativeButton("关闭",
                new DialogInterface.OnClickListener() {
                    @Override
                    public void onClick(DialogInterface dialog, int which) {
                        //...To-do
                    }
                });
        // 显示
        /**
         * AlertDialog.Builder直接show的话，确实显示的是带\n的文本不换行
         * dialog.show();（\n不换行）
         *
         * AlertDialog.Builder先create再show就能正确换行。
         * dialog.create().show();（\n能换行）
         */
        dialog.create().show();
    }

    /*
    倒计时方案一：
    private void timeout() {
        txtView = findViewById(R.id.txtTime);
        handler.postDelayed(runnable, 0);
    }

    Handler handler = new Handler();
    Runnable runnable = new Runnable() {
        @Override
        public void run() {
            recLen++;
            txtView.setText("" + recLen);
            handler.postDelayed(this, 1000);
        }
    };


    倒计时方案二：
    private Handler handler = new Handler(){
        @Override
        public void handleMessage(@NonNull Message msg) {
            txtView.setText(msg.arg1 + "");
            timeStart();
        }
    };

    private void timeStart(){
        timeIsStart = true;
        timer = new Timer();
        task = new TimerTask() {
            @Override
            public void run() {
                i--;
                Message message = handler.obtainMessage();
                message.arg1 = i;
                handler.sendMessage(message);
            }
        };
        timer.schedule(task,1000);
    }

    private void timeStop(){
        timeIsStart = false;
        timer.cancel();
    }
    */

    /**
     * 游戏开始，开始计时，当执棋方落子后重置原先计时，重新开始计时（30s）
     * 计时达20s时，时间字体颜色变为红色，Toast警告即将超时！！！
     * 超出规定时间（30s）未落子，即判定为认输。
     */
}